package com.piece.core.web.controller;

import com.piece.core.framework.constant.*;
import com.piece.core.framework.enums.sql.SqlKey;
import com.piece.core.framework.exception.ServerException;
import com.piece.core.framework.support.bootstrap.Order;
import com.piece.core.framework.support.bootstrap.QueryTable;
import com.piece.core.framework.support.bootstrap.TreeData;
import com.piece.core.framework.support.convert.Convert;
import com.piece.core.framework.support.response.AjaxResponse;
import com.piece.core.framework.util.cache.CacheFactory;
import com.piece.core.framework.util.object.ObjectUtil;
import com.piece.core.framework.util.object.BeanUtil;
import com.piece.core.framework.util.object.ClassUtil;
import com.piece.core.framework.util.basic.I18nUtil;
import com.piece.core.framework.util.string.StringUtil;
import com.piece.core.framework.util.time.DateUtil;
import com.piece.core.framework.properties.ApplicationProperties;
import com.piece.core.web.cookie.CookieUtil;
import com.piece.core.web.util.ServletUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.beans.PropertyEditorSupport;
import java.lang.reflect.Field;
import java.util.*;

/**
 * Controller通用数据处理
 */
@Slf4j
public class FrameWorkController {

    @Value("${spring.resources.context:#{'/'}}")
    protected String contextPath;

    @Autowired
    protected ApplicationProperties applicationProperties;

    @Autowired
    protected CacheFactory cacheFactory;

    /**
     * 将前台传递过来的日期格式的字符串，自动转化为Date类型
     */
    @InitBinder
    public void initBinder(WebDataBinder binder) {
        // Date 类型转换
        binder.registerCustomEditor(Date.class, new PropertyEditorSupport() {
            @Override
            public void setAsText(String text) {
                setValue(DateUtil.getDate(text));
            }
        });
    }

    /**
     * 得到request对象
     */
    public HttpServletRequest getRequest() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        return request;
    }

    /**
     * 得到response对象
     */
    public HttpServletResponse getResponse() {
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        return response;
    }

    /**
     * 得到session对象
     */
    public HttpSession getSession() {
        HttpSession session = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getSession(false);
        return session;
    }

    public String getToken() {
        return extractHeaderToken(getRequest());
    }

    private String extractHeaderToken(HttpServletRequest request) {
        Enumeration headers = request.getHeaders(HeaderConstants.Authorization);

        String value;
        do {
            if (!headers.hasMoreElements()) {
                return null;
            }

            value = (String)headers.nextElement();
        } while(!value.toLowerCase().startsWith(FrameWorkConstants.BEARER_TYPE.toLowerCase()));

        String token = value.substring(FrameWorkConstants.BEARER_TYPE.length()).trim();
        int commaIndex = token.indexOf(44);
        if (commaIndex > 0) {
            token = token.substring(0, commaIndex);
        }

        if (null == token) {
            token = request.getParameter(ParamConstants.TOKEN);
        }

        if (null == token) {
            token = CookieUtil.getCookieValue(request, CookieConstants.SESSION_KEY);
        }

        return token;
    }

    public String getLanguage() {
        return LocaleContextHolder.getLocale().getDisplayLanguage();
    }

    public boolean isChinese() {
        return LocaleContextHolder.getLocale().equals(Locale.SIMPLIFIED_CHINESE);
    }

    /**
     * 请求内容转换成对象
     */
    public void initDB(Object obj) {
        initDB(obj, null);
    }

    /**
     * 请求内容转换成对象
     */
    public void initDB(Object obj, String prefix) {
        HttpServletRequest request = getRequest();
        //查询条件
        Enumeration<?> enu = request.getParameterNames();
        while (enu.hasMoreElements()) {
            String paraName = (String) enu.nextElement();
            String prefixName = "";
            if (StringUtil.isNotEmpty(prefix)) {
                prefixName = prefix;
                if (paraName.startsWith(prefix))
                    paraName = paraName.replace(prefix, "");
                else
                    paraName = null;
            }
            if (StringUtil.isNotEmpty(paraName)) {
                try {
                    Object value = null;
                    boolean update = false;
                    String mapKey = null;
                    if (paraName.indexOf("[") < 0) {
                        value = request.getParameter(prefixName + paraName);
                        if (StringUtil.isEmptyParameter(value.toString())) {
                            value = null;
                        }
                    } else {
                        String[] arr = request.getParameterValues(prefixName + paraName);
                        update = true;
                        if (!ObjectUtil.isEmpty(arr)) {
                            value = StringUtil.join(arr, FrameWorkConstants.SPLIT_PARAM);
                        }

                        mapKey = StringUtil.extractMessage(paraName, "[", "]");
                        paraName = paraName.replace("[" + mapKey + "]", "");
                    }

                    Field field = BeanUtil.getFieldByFieldName(obj.getClass(), paraName);
                    if (null == field) {
                        continue;
                    }
                    // 不为非基础类赋值
                    if (!ClassUtil.isJavaClass(field.getType())) {
                        continue;
                    }

                    try {
                        if (update) {
                            // 如果为Map类型
                            if (Map.class == field.getType()) {
                                Map<String, Object> variables = (Map<String, Object>) BeanUtil.getFieldValue(obj, field);
                                if (null == variables) {
                                    variables = new HashMap<>();
                                }
                                variables.put(mapKey, value);
                                BeanUtil.updateFieldValue(obj, field, variables);
                            } else {
                                BeanUtil.updateFieldValue(obj, field, value);
                            }
                        } else {
                            BeanUtil.setFieldValue(obj, paraName, value);
                        }
                    } catch (Exception e) {
                    }
                } catch (Exception e) {
                    throw new ServerException(e.getMessage());
                }
            }
        }
    }

    /**
     * 请求内容转换成对象
     */
    public void initMap(Map<String, Object> obj) {
        initMap(obj, null);
    }

    /**
     * 请求内容转换成对象
     */
    public void initMap(Map<String, Object> obj, String prefix) {
        HttpServletRequest request = getRequest();
        //查询条件
        Enumeration<?> enu = request.getParameterNames();
        while (enu.hasMoreElements()) {
            String paraName = (String) enu.nextElement();
            String prefixName = "";
            if (StringUtil.isNotEmpty(prefix)) {
                prefixName = prefix;
                if (paraName.startsWith(prefix))
                    paraName = paraName.replace(prefix, "");
                else
                    paraName = null;
            }
            if (StringUtil.isNotEmpty(paraName)) {
                Object value = null;
                if (paraName.indexOf("[") < 0) {
                    value = request.getParameter(prefixName + paraName);
                    if (StringUtil.isEmptyParameter(value.toString())) {
                        value = null;
                    }
                } else {
                    //传的是数组
                    String[] arr = request.getParameterValues(paraName);
                    if (!ObjectUtil.isEmpty(arr)) {
                        value = StringUtil.join(arr, FrameWorkConstants.SPLIT_PARAM);
                    }

                    String temp = StringUtil.extractMessage(paraName, "[", "]");
                    paraName = paraName.replace("[" + temp + "]", "");

                    String last = Convert.toStr(obj.get(paraName), null);
                    if (ObjectUtil.isNotNull(last) && ObjectUtil.isNotNull(value)) {
                        value = last + FrameWorkConstants.SPLIT_PARAM + value;
                    }
                }
                obj.put(paraName, value);
            }
        }
    }

    /**
     * 用于分页、排序
     */
    @SuppressWarnings("rawtypes")
    public QueryTable initTable() {
        QueryTable table = new QueryTable();
        table.setStart(0);
        HttpServletRequest request = this.getRequest();
        //查询条件
        Map<String, Object> paramMap = table.getParams();
        if (null == paramMap) paramMap = new HashMap<>();
        List<Order> orders = new ArrayList<>();
        Enumeration enu = request.getParameterNames();
        while (enu.hasMoreElements()) {
            String paraName = (String) enu.nextElement();
            if (StringUtil.isNotEmpty(paraName)) {
                Object value = request.getParameter(paraName);
                //设置分页
                if ("offset".equals(paraName)) {
                    try {
                        int length = Convert.toInt(table.getLength(), FrameWorkConstants.PAGE_SIZE);
                        table.setStart(null == value ? 0 : Integer.parseInt(value.toString()));
                        table.setCurrentPage((table.getStart() + table.getLength()) / length);
                    } catch (Exception e) {
                        table.setStart(0);
                        table.setCurrentPage(1);
                    }
                    continue;
                }
                if ("page".equals(paraName)) {
                    try {
                        int length = Convert.toInt(table.getLength(), FrameWorkConstants.PAGE_SIZE);
                        table.setCurrentPage(null == value ? 1 : Integer.parseInt(value.toString()));
                        table.setStart((table.getCurrentPage() - 1) * length);
                    } catch (Exception e) {
                        table.setStart(0);
                        table.setCurrentPage(1);
                    }
                    continue;
                }
                if ("limit".equals(paraName)) {
                    try {
                        table.setLength(null == value ? FrameWorkConstants.PAGE_SIZE : Integer.parseInt(value.toString()));
                    } catch (Exception e) {
                        table.setLength(0);
                    }
                    continue;
                }
                //设置排序 bootstrap-table表格参数
                if ("sort".equals(paraName)) {
                    String disc = request.getParameter("order");
                    String attr = Convert.toStr(value);
                    if (StringUtil.isNotEmpty(attr) && StringUtil.isNotEmpty(disc)) {
                        if (SqlKey.ASC.getType().equalsIgnoreCase(disc)) {
                            orders.add(new Order(attr, SqlKey.ASC));
                        } else {
                            orders.add(new Order(attr, SqlKey.DESC));
                        }
                    }
                    continue;
                }
                if ("order".equals(paraName)) {
                    continue;
                }
                if ("alias".equals(paraName)) {
                    table.setAlias(Convert.toStr(value));
                }
                //设置查询条件
                if (paraName.startsWith("Q_") && null != value) {
                    String condition = paraName.split(FrameWorkConstants.SEPARATOR)[3];
                    if (!StringUtil.isEmptyParameter(value.toString())) {
                        paramMap.put(paraName, value);
                    } else if (StringUtil.getIndexOfString(condition, new String[]{"EMP", "NEMP", "NULL", "NNULL"}) != -1) {
                        paramMap.put(paraName, null);
                    }
                }
            }
        }
        //设置起始值
        if (null != table.getCurrentPage() && null != table.getLength()) {
            table.setStart((table.getCurrentPage() - 1) * table.getLength());
        }
        if (null == table.getLength() || table.getLength() <= 0) {
            table.setLength(0);
        }

        table.setParams(paramMap);
        table.setOrder(orders);
        return table;
    }

    /**
     * 用于select2下拉框
     */
    public QueryTable initSelect(String param) {
        QueryTable table = new QueryTable();
        HttpServletRequest request = this.getRequest();
        //查询条件
        Map<String, Object> paramMap = table.getParams();
        if (null == paramMap) paramMap = new HashMap<>();
        String key = request.getParameter("term");
        String page = request.getParameter("page");
        String length = request.getParameter("length");
        table.setCurrentPage(null == page ? 1 : Integer.parseInt(page));

        try {
            table.setLength(null == length ? 0 : Integer.parseInt(length));
        } catch (NumberFormatException e) {
            table.setLength(0);
        }
        table.setStart((table.getCurrentPage() - 1) * table.getLength());
        if (StringUtil.isNotEmpty(param) && StringUtil.isNotEmpty(key)) {
            String[] params = param.split(FrameWorkConstants.SPLIT_PARAM);
            for (int i = 0; i < params.length; i++) {
                paramMap.put(params[i], key);
            }
        }
        table.setParams(paramMap);
        return table;
    }

    /**
     * 设置request属性信息
     */
    protected void setParameter(String name, String value) {
        if (StringUtil.isNotEmpty(value)) {
            getRequest().setAttribute(name, value);
        }
    }

    /**
     * 根据父节点的ID获取所有子节点
     */
    public List<TreeData> findChildTreeData(List<TreeData> list, String parentId) {
        List<TreeData> returnList = new ArrayList<>();
        for (Iterator<TreeData> iterator = list.iterator(); iterator.hasNext();) {
            TreeData tree = iterator.next();
            // 根据传入的某个父节点ID,遍历该父节点的所有子节点
            if (Convert.toStr(tree.getPId(), "root").equals(parentId)) {
                recursionFn(list, tree);
                returnList.add(tree);
            }
        }
        return returnList;
    }

    /**
     * 递归列表
     */
    private void recursionFn(List<TreeData> list, TreeData tree) {
        // 得到子节点列表
        List<TreeData> childList = getChildList(list, tree);
        tree.setChildren(childList);
        if (CollectionUtils.isNotEmpty(childList)) {
            tree.setParent(true);
        } else {
            tree.setParent(false);
            tree.setChildren(null);
        }
        for (TreeData tChild : childList) {
            if (hasChild(list, tChild)) {
                // 判断是否有子节点
                Iterator<TreeData> it = childList.iterator();
                while (it.hasNext()) {
                    TreeData n = it.next();
                    recursionFn(list, n);
                }
            }
        }
    }

    /**
     * 判断是否有子节点
     */
    private boolean hasChild(List<TreeData> list, TreeData tree) {
        return getChildList(list, tree).size() > 0;
    }

    /**
     * 获取子节点列表
     */
    private List<TreeData> getChildList(List<TreeData> list, TreeData tree) {
        List<TreeData> c_list = new ArrayList<>();
        Iterator<TreeData> it = list.iterator();
        while (it.hasNext()) {
            TreeData n = it.next();
            if (n.getPId().equals(tree.getId())) {
                c_list.add(n);
            }
        }
        return c_list;
    }

    /**
     * 响应返回结果
     *
     * @param rows 影响行数
     * @return 操作结果
     */
    protected AjaxResponse ajaxResponse(int rows) {
        return rows > 0 ? success() : error();
    }

    /**
     * 响应返回结果
     *
     * @param result 结果
     * @return 操作结果
     */
    protected AjaxResponse ajaxResponse(boolean result) {
        return result ? success() : error();
    }

    /**
     * 返回成功
     */
    public AjaxResponse success() {
        return AjaxResponse.success(I18nUtil.message(ExceptionConstants.MESSAGE_SUCCESS));
    }

    /**
     * 返回成功消息
     */
    public AjaxResponse success(Object response) {
        return AjaxResponse.success(I18nUtil.message(ExceptionConstants.MESSAGE_SUCCESS), response);
    }

    /**
     * 返回成功消息
     */
    public AjaxResponse success(String msg, Object response) {
        return AjaxResponse.success(msg, response);
    }

    /**
     * 返回失败消息
     */
    public AjaxResponse error() {
        return AjaxResponse.error(I18nUtil.message(ExceptionConstants.MESSAGE_ERROR));
    }

    /**
     * 返回失败消息
     */
    public AjaxResponse error(String message) {
        return AjaxResponse.error(message);
    }

    /**
     * 返回错误码消息
     */
    public AjaxResponse error(int code, String message) {
        return AjaxResponse.error(code, message);
    }

    /**
     * 返回错误码消息
     */
    public AjaxResponse error(String message, Object response) {
        return AjaxResponse.error(500, message, response);
    }

    /**
     * 页面跳转
     */
    public String redirect(String url) {
        return StringUtil.format("redirect:{}", getRequestPrefix() + url);
    }

    /**
     * 页面跳转
     */
    public String forward(String url) {
        if (!url.startsWith("/")) {
            return StringUtil.format("forward:/{}", getRequestPrefix() + url);
        }
        return StringUtil.format("forward:{}", getRequestPrefix() + url);
    }

    /**
     * 获取url请求前缀
     */
    public String getRequestPrefix() {
        String context = ServletUtil.getRequestPrefix(contextPath);
        return context.substring(0, context.length() - 1);
    }
}
